#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h> // for close

#define SUCCESS 0
#define DEFAULT_PORT 9696
#define BACKLOG 96

const char http_response[] = 
    "HTTP/1.1 200 OK\n"
    "Content-Type: text/html\n"
    "Content-Length: 11\n"
    "\n"
    "hello world";

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(1);
    }

    uint16_t port = DEFAULT_PORT;
    {
        char *endptr;
        port = (uint16_t) strtol(argv[1], &endptr, 10);

        if (endptr == argv[1]) {
            fprintf(stderr, "could not parse port %s\n", argv[1]);
            exit(1);
        }
    }

    fprintf(stdout, "starting server on port %u\n", port);

    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        fprintf(stderr, "could not create server %s\n", strerror(errno));
        exit(1);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    int result = bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
    if (result != SUCCESS) {
        fprintf(stderr, "could not bind server %s\n", strerror(errno));
        close(server_fd);
        exit(1);
    }

    result = listen(server_fd, BACKLOG);
    if (result != SUCCESS) {
        fprintf(stderr, "could not listen server %s\n", strerror(errno));
        close(server_fd);
        exit(1);
    }

    for (;;) {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        int client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &client_addr_len);
        if (client_fd < 0) {
            fprintf(stderr, "could not accept client %s\n", strerror(errno));
            continue;
        }

        ssize_t error = send(client_fd, http_response, sizeof(http_response) - 1, 0);
        if (error < 0) {
            fprintf(stderr, "could not write to client %s\n", strerror(errno));
        }
        close(client_fd);
    }

    close(server_fd);
    return 0;
}
